home *** CD-ROM | disk | FTP | other *** search
/ Disc to the Future 2 / Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin / MAC / THINKC / 3_0 / RAMSTART / RS(MAIN).C < prev   
Text File  |  1988-01-17  |  28KB  |  922 lines

  1. /*
  2. RS(Main).c        RamStart
  3.  
  4. By:  George A. Nelson    on     1 February 1985
  5.                             19 March   1985    ver 1
  6.                             15 May       1985    ver 1.1
  7.                             10 July    1985    ver 1.11
  8.                             24 July    1985    ver 1.2
  9.                              2 August  1985    ver 1.21
  10.                             23 August  1985 ver 1.22
  11.                              4 May     1986    ver 1.23
  12.                             25 May       1986    ver 1.24
  13.                             20 August  1986    ver 1.3
  14.                             17 October 1986 ver 1.31
  15.                             4 February 1987 ver 1.32
  16.                             28 March   1987 ver 1.4
  17.                             11 January 1988 ver 1.41
  18.  
  19. Description:  Excellent RAM disk derived from Apple's sample, (c) Apple
  20.     Computer 1983, written Dec '83 by MDB (?).  This version is re-sizable
  21.     and re-inserts itself when ejected.  RamStart copies all files in its
  22.     own    folder or named in a text file to the new RAM disk, and, if a
  23.     System and a Finder (or the application named in the text file) were
  24.     copied, ejects its disk and starts the Finder on the RAM disk.
  25.     
  26.     While I try to follow the user interface guidelines, this is not an
  27.     event-driven program.  When it is copying files, it can be a bit slow
  28.     to respond to the user's pressing a control.
  29.   
  30.     When invoked for the first time in a session (usually as the startup
  31.     program), RamStart reserves space for the RAM disk.  The memory is
  32.     actually only reserved by the Segment Loader when the application heap
  33.     zone is initialized, so RamStart launches itself to cause this.  It is
  34.     during the second run that the RAM disk is created and files are copied
  35.     to it.  RamStart then starts the Finder on the RAM disk (if a System
  36.     and a Finder were copied).
  37.     
  38.     If RamStart finds that there is already a RAM disk in memory (on third
  39.     and subsequent runs), it give the user the choice of what to do.
  40.     
  41.     This program must overcome a major communications problem.  Variables
  42.     known to one section of code are unavailable to others, since they
  43.     occur in different runs!  From the first run of the program, when
  44.     memory is reserved, to the second, when the RAM disk driver is opened
  45.     to create the RAM disk, the location of the RAM disk is remembered in a
  46.     low memory global, ApplScratch.  This seems to cause Microsoft programs
  47.     to forget that they have seen the original master disk.  Too bad.  When
  48.     the program is run again, by accident or to change or remove the RAM
  49.     disk, this value may no longer be good -- another application may have
  50.     used ApplScratch.  The driver refNum is reconstructed from the DRVR
  51.     resource, whose name we know.  If the RAM disk driver is present, it
  52.     responds to a Status call with a record containing its signature (so we
  53.     can be sure that our driver responded, and not, say, the Assimilation
  54.     Process RAM disk), and a handle containing a pointer to the RAM disk,
  55.     the old value of BufPtr (we set BufPtr to point to the RAM disk to
  56.     reserve its memory), and a pointer to the drive queue entry.
  57.     
  58.     RamStart determines which run it is in when it starts up.  First it
  59.     tries to get the driver's status; if it can, it is in "phase 3".
  60.     Otherwise, it checks ApplScratch for the signature; if it finds one it
  61.     is in "phase 2".  Otherwise it is in "phase 1".
  62.     
  63.     Apple (Harvey Alcabes) suggests that driver (and desk accessory)
  64.     numbers should be assigned "on the fly".  When installing a driver in a
  65.     System file, this means to use an unused resource id.  My driver, by
  66.     not being installed in any System file, illustrates the problems with
  67.     Apple's "solution", which is that the startup disk can change with each
  68.       application launch, while drivers typically remain open.  Who can tell
  69.     what conflict will arise with another System file?  Instead, RamStart
  70.     is shipped with the driver ID set to be the same as Assimilation's, 11,
  71.     so all RAM disk users will experience the same conflicts.
  72.  
  73. Related files:
  74.   RS(Copy).c
  75.   RS(Dlog).c
  76.   RS.h
  77.   RamDisk.asm
  78.   RamStart.r
  79.   RamIcon
  80. //
  81. Bugs:
  82.   13 March 85.  Driver #10 is also the AppleBus.  What driver number
  83.     would be safer?  (17 April 85.  Apple has only a scummy kludge to
  84.     offer:  pick an unused number at open time and hope that it doesn't
  85.     conflict with a driver in any subsequent active System file.)
  86.   
  87.   14 March 85.  The System file can't be copied from the RAM disk.  I set
  88.     the Protected bit to cause this, 'cause copying it to a real disk
  89.     makes the real disk unbootable.  The boot blocks on the RAM disk are
  90.     not inited, and the Finder copies them too when it copies the System.
  91.   
  92.   2 April 85.  Fixed.  NoRamDisk() was causing the screen to be trashed by
  93.     changing BufPtr before the RAM disk went away.  This points up the
  94.     communications problems in the program.
  95.   
  96.   17 May 85.  Fixed.  The new multiple-opens CopyFolder() would not copy
  97.     more files than fit in one pass.  A comment claimed that the last file
  98.     opened was closed to ensure that a destination file would be opened;
  99.     this was not done and wouldn't have worked anyway (how to copy the last
  100.     file?).  A new subroutine checks whether a file can be opened; if not,
  101.     it finds a file to close, which will be copied next time.  Poor testing.
  102.   
  103.   10 July 85.  Fixed.  Bundle bit now set.  Shows proper version data, and
  104.     contains proper version data in resource file.  Slight changes to help
  105.     file.
  106.   
  107.   17 July 85.  U Alberta asked for a version that would make it hard to copy
  108.     files from the RAM disk.  Compile-time switch sets protected bit on all
  109.     files.
  110.     
  111.     Why did I think that my "protect" code worked?  The new code, copied
  112.     from Examine File, does.
  113.   
  114.   2 Aug 85.  Changed rules for getting RamStart to keep the ducks at bay.
  115.   
  116.   23 Aug 85.  Fixed RTE in driver.  I hadn't understood why the original
  117.     RAM disk driver did this; neither had the author.  It was for asynch
  118.     routines that had disabled vertical retrace interrupts.  It doesn't
  119.     work on the 68010.  Reported by Levco.
  120.   
  121.   21 March 86.  Version for HFS, at Consulair's request.  This should be
  122.     the last free version, barring other bug fixes.
  123.   
  124.   2 May 86.  Still HFS version.  Removed Protect() code; it fails under HFS.
  125.     Put INIT's and data fork back in System file.  Sat to make it bigger,
  126.     but it's the only safe thing to do.
  127.   
  128.   21 May 86.  Crashes if trying to remove an old-version RAM disk on a Mac+./
  129.   
  130.   25 May 86, 1.24.  Re-inserts based on actual drive number, rather than
  131.     hardwired "drive 3".
  132.     
  133.     HFS 3.1.1 and 1.1a3 do not pass "eject" for non-ejectable volumes -- and
  134.     don't return an error code and still allow the volume to be unmounted!
  135.     Apple's bug prevents RAM disk from re-inserting.
  136.     
  137.   20 August 86, 1.3.  Converted to LightspeedC.  Now sets size of drive in
  138.     drive queue element (still can't format from Finder with DI pack).
  139.     Fixed bug in copying many files -- would leave out the last one of a
  140.     batch -- using a simpler method for finding the number of files that
  141.     can be opened.  Now says "opening..." as well as "copying..." -- HFS
  142.     can be _very_ slow opening files (use MFS instead).  Improved error
  143.     reporting: can now print a string, such as a file name.
  144.   
  145.   17 October 86, 1.31.  Steve Hanna reported bug, miscalled _HandToHand
  146.     (the interface had changed from Consulair).  This caused a crash when
  147.     a ".ram" file was changed to a RamStart Script document.
  148.  
  149.   4 February 87, 1.32.  Now hides more types of "system" file, notably
  150.     printer drivers.  Converted to LightSpeedC ver 2.01, using its HFS
  151.     definitions.  New item in Already dialog to tell user why the RAM
  152.     disk can't be removed.  Version intended for distribution by Apple.
  153.  
  154.   28 March 87, 1.4.  Added "many little files" box, which triples the
  155.     size of the RAM disk directory.  Unchecked, there is 1 dir block for
  156.     every 40K of disk space, or enough for 6K byte average files.  Checked
  157.     there are 3 dir blocks for every 40K of disk space, or enough for 2K
  158.     byte average files.  The option is useful for a RAM disk of header
  159.     files.
  160.  
  161.   10 January 88, 1.41.  Faster clear of RAM disk storage when opened.
  162.     Changed my address.  Minor changes to documentation.  Declaration of
  163.     controlParam structure of RamStatusPB placed in line; Think has
  164.     screwed up the definition in DeviceMgr.h.  Now close last file being
  165.     copied to the RAM disk in CloseFiles() (when copying is aborted);
  166.     Apple changed UnmountVol for Multifinder and it no longer closes files
  167.     but gives an error instead.  Added yet more types to "hide me" list
  168.     in CopyFile().
  169. */
  170.  
  171. /* //  */
  172. #include <MacTypes.h>
  173. #include <DialogMgr.h>
  174. #include <MemoryMgr.h>
  175. #include <ResourceMgr.h>
  176. #include <FileMgr.h>
  177. #include <DeviceMgr.h>
  178. #include <ToolboxUtil.h>
  179. #include <SegmentLdr.h>
  180. #include <SetJmp.h>
  181.  
  182. #include "RS.h"
  183.  
  184.  
  185. /* Defined here */
  186.  
  187. typedef struct {                /* Info similar to RamInfo, passed from phase 0 */
  188.     long        signature;        /*   to phase 1. */
  189.     char        *oldBufPtr;
  190.     short        initCmd;        /* 'BD' requests big dir from the driver open */
  191.     short        initVal;        /* size factor for big directory */
  192. } ApplInfo;
  193. #define applInfo (*(ApplInfo *)&ApplScratch)
  194.  
  195. typedef struct {
  196.     struct {
  197.         QElemPtr    qLink;
  198.         int            qType;
  199.         int            ioTrap;
  200.         Ptr            ioCmdAddr;
  201.         ProcPtr        ioCompletion;
  202.         OsErr        ioResult;
  203.         StringPtr    ioNamePtr;
  204.         int            ioVRefNum;
  205.         int            ioRefNum;
  206.         int            csCode;
  207.         int            csParam[];
  208.     }            pb;
  209.     RamStatus    stat;
  210. } RamStatusPB;
  211.  
  212.  
  213. RamInfo            ramInfo;        /* For NoRamDisk() and MakeCtlW(). */
  214. short            ramID;            /* " */
  215.  
  216.  
  217. char copyRight[] = "\pāŒ1985-1988 George A. Nelson; portions āŒ1983 Apple Computer.";
  218.  
  219.  
  220. jmp_buf            env;            /* for TestDlog() */
  221.  
  222.  
  223. short    MakeRamDisk();
  224. short    UnusedDrive();
  225. short    DoAlready();
  226. char    CopyFolder();
  227.  
  228. /* //  */
  229. main()
  230. {
  231.     short        mssg;
  232.     
  233.     
  234.     if( Button()  &&  TraceTrap < ROMBase )        /* break to the debugger, if one is present */
  235.         Debugger();
  236.     
  237.     
  238.     InitGraf( &thePort );
  239.     InitFonts();
  240.     InitWindows();
  241.     TEInit();                                    /* required for dialogs */
  242.     InitMenus();                                /* required for dialogs? */
  243.     InitDialogs( NULL );
  244.  
  245.     SetCursor( *GetCursor(watchCursor) );
  246.     
  247.     
  248.     /* Catch a signal from TestDLOG and call GetNewSize().  This allows
  249.     other routines to clean up first. */
  250.     
  251.     if( (mssg = setjmp(env)) ) {
  252.         if( mssg == 'SZ' )
  253.             GetNewSize();
  254.         else error( "\pUnknown setjmp() message ^2", (long)mssg );
  255.     }
  256.     
  257.     
  258.     /* set ramID to the RAM disk driver refNum from the driver resource */  
  259.     {
  260.         Handle        dh;
  261.         long        rType;
  262.         Str255        rName;
  263.         
  264.         
  265.         SetResLoad( FALSE );
  266.         dh = GetNamedResource('DRVR', RamName );
  267.         SetResLoad( TRUE );
  268.         
  269.         GetResInfo( dh, &ramID, &rType, &rName );    /* ramID is global. */
  270.     }
  271.   
  272. /* //  */
  273.     /* Ask the driver if we are in phase 3.  If not, check ApplScratch to
  274.     see if we are in phase 2.  Otherwise, we are in phase 1 ('cause nothing
  275.     was set up yet). */
  276.     
  277.     {
  278.         RamStatusPB    ramStatusPB;
  279.         short        actualRamID;
  280.         Boolean        diskExists = FALSE;
  281.         
  282.         
  283.         Clear( ramStatusPB );
  284.         ramStatusPB.pb.ioRefNum = ~(actualRamID = ramID);
  285.         
  286.         if( PBStatus(&ramStatusPB, FALSE) == noErr  &&  ramStatusPB.stat.signature == RamSignature )
  287.             diskExists = TRUE;
  288.     
  289.         else {
  290.             Clear( ramStatusPB );
  291.             ramStatusPB.pb.ioRefNum = ~10;        /* Driver refNum we used to use. */
  292.             
  293.             if( PBStatus(&ramStatusPB, FALSE) == noErr  &&  ramStatusPB.stat.signature == RamSignature ) {
  294.                 diskExists = TRUE;
  295.                 actualRamID = 10;
  296.             }
  297.         }
  298.         
  299.         
  300.         if( diskExists )
  301.         {
  302.             DoPhase3( &ramStatusPB, actualRamID );  
  303.         }
  304.         else if( applInfo.signature == RamSignature )
  305.             DoPhase2();
  306.         
  307.         else DoPhase1();
  308.     }
  309. }
  310.  
  311. /* //  */
  312. /* The phases follow.  Each phase is a different run of the program.
  313. Variables cannot be passed from one phase to another!  Instead, low memory
  314. locations or handles to data in the system heap are used. */
  315.  
  316.  
  317. /* In phase 1.  No RAM disk is installed.  Reserve memory for a RAM disk
  318. and run again to get that memory reserved. */
  319.  
  320. #define round 40
  321. #define hrTop 50
  322. #define hrLeft 140
  323. #define hrBottom 132
  324. #define hrRight 372
  325. #define irTop ((hrTop+hrBottom-32)/2)
  326. #define irLeft (hrLeft+30)
  327. #define irBottom (irTop+32)
  328. #define irRight (irLeft+32)
  329.  
  330. DoPhase1()
  331. {
  332.     long        heapSize, dirSize;
  333.     Ptr            ramStart;
  334.     short        i, lMargin;
  335.     char        *version, **versionH, *ctrlFileName;
  336.     static Rect helloR = { hrTop, hrLeft, hrBottom, hrRight },
  337.                 iconR  = { irTop, irLeft, irBottom, irRight };
  338.     
  339.     
  340.     /* say hello */
  341.     
  342.     versionH = GetResource( 'GANr', 0 );
  343.     DetachResource( versionH );
  344.     HLock( versionH );
  345.     version = *versionH;
  346.     
  347.     for( i = 1;  i < version[0];  ++i ) {        /* keep only version data */
  348.         if( version[i] == ',' )
  349.             version[0] = i - 1;
  350.     }
  351.     
  352.     lMargin = ( irRight + hrRight - StringWidth(version) - 5 )/2;
  353.     
  354.     PenNormal();
  355.     PenSize( 5, 5 );
  356.     FillRoundRect( &helloR, round, round, &white );
  357.     FrameRoundRect( &helloR, round, round );
  358.     
  359.     PlotIcon( &iconR, GetResource('ICN#', 128) );
  360.     
  361.     MoveTo( lMargin, (hrTop + hrBottom)/2 - 10 );
  362.     DrawString( version );
  363.     MoveTo( lMargin, (hrTop + hrBottom)/2 + 6);
  364.     DrawString( "\pHFS compatible" );
  365. /* //  */
  366.     
  367.     /* reserve the RAM disk memory */
  368.     
  369.     GetCtrlFile( &ctrlFileName );
  370.     heapSize = *(long *)*GetResource( 'RAMD', 256 );
  371.     dirSize  = *(long *)*GetResource( 'RAMD', 257 );
  372.     ramStart = (Ptr)GetZone() + heapSize;
  373.     
  374.     InitRamDisk( heapSize, ramStart, dirSize );    /* May not return. */
  375.     ReStartUs();                                /* Never returns. */
  376. }
  377.  
  378. /* //  */
  379. /* In phase 2.  By now, there is space for the RAM disk. */
  380.  
  381. DoPhase2()
  382. {
  383.     long        size;
  384.     short        ramDrvNum, ramRefNum, go;
  385.     RamStatusPB    ramStatusPB;
  386.     char        *ctrlFileName, *exitAppl;
  387.     DialogPtr    threat;
  388.     
  389.     
  390.     ramInfo.ramDisk = BufPtr;
  391.     ramInfo.oldBufPtr = applInfo.oldBufPtr;
  392.     size = ramInfo.oldBufPtr - ramInfo.ramDisk; /* Size of RAM disk. */
  393.     applInfo.signature = 0;                        /* don't do phase 2 again */
  394.   
  395.     if( size < MinDisk ) {
  396.         error("\pRAM disk not properly inited, old BufPtr=^2, BufPtr=^3", ramInfo.oldBufPtr, BufPtr);
  397.         size = MinDisk;
  398.     }
  399.     
  400.     threat = GetNewDialog( dlogThreat, NULL, -1 );    /* "Free" means don't sell RamStart! */
  401.     BeginUpdate( threat );                        /* Normally done via Update event. */
  402.     DrawDialog( threat );
  403.     EndUpdate( threat );
  404.     
  405.     GetCtrlFile( &ctrlFileName );
  406.     MakeCtlW( size );
  407.     
  408.     
  409.     ramRefNum = MakeRamDisk();
  410.     ramDrvNum = UnusedDrive();
  411.     ChgDrvQ( ramRefNum, ramDrvNum, size );        /* Even if the new drive claims not to be write */
  412.     FixVolInfo( ramDrvNum );                    /*   protected, this must be done. */
  413.     ZapControlFile( ramDrvNum );
  414.     
  415.     
  416.     /* Save ramInfo for next phase.  Use driver's data handle. */
  417.     
  418.     Clear( ramStatusPB );
  419.     ramStatusPB.pb.ioRefNum = ~ramID;
  420.     
  421.     if( PBStatus(&ramStatusPB, FALSE) == noErr  &&  ramStatusPB.stat.signature == RamSignature ) {
  422.         SetHandleSize( ramStatusPB.stat.ramInfoh, sizeof(RamInfo) );
  423.         (*ramStatusPB.stat.ramInfoh)->oldBufPtr = ramInfo.oldBufPtr;
  424.         (*ramStatusPB.stat.ramInfoh)->drvQEntry = ramInfo.drvQEntry;
  425.     }
  426.     else {
  427.         error("\pcan't get RAM disk driver status, ioResult=^2", (long)ramStatusPB.pb.ioResult);
  428.         ExitToShell();
  429.     }
  430.     
  431.     
  432.     /* Copy the files to the RAM disk. */
  433.     
  434.     exitAppl = FinderName;                        /* default, may be changed if there is a control file */
  435.     
  436.     if( ctrlFileName )
  437.         go = CopyCtrlFile( ctrlFileName, ramDrvNum, &exitAppl );
  438.     else
  439.         go = CopyFolder( ramDrvNum, CurApName, FinderName );
  440.     
  441.     if( go == (HadSystem + HadFinder) )        /* TRUE if had a System and a Finder. */
  442.         LaunchRamDisk( ramDrvNum, exitAppl );
  443. }
  444.  
  445. /* //  */
  446. /* In phase 3.  A RAM disk is already installed.  Set the info needed by
  447. NoRamDisk().  Ask the user what to do:  leave the RAM disk alone, remove
  448. it, or replace it with a new one. */
  449.  
  450. DoPhase3( ramStatusPBp, actualRamID )
  451. RamStatusPB        *ramStatusPBp;
  452. short            actualRamID;
  453. {
  454.     long        size, itemHit, heapSize, dirSize;
  455.     Ptr            ramStart;
  456.     char        *ctrlFileName;
  457.     short        oldRamID;
  458.     
  459.     
  460.     ramInfo = **ramStatusPBp->stat.ramInfoh;
  461.     size = ramInfo.oldBufPtr - ramInfo.ramDisk;    /* Size of RAM disk. */
  462.     
  463.     itemHit = DoAlready( (long)ramInfo.drvQEntry & ~1L );    /* Ask the user. */
  464.     
  465.     if( itemHit != alreadyIQuit ) {
  466.         oldRamID = ramID;                        /* Either New or Remove. */
  467.         ramID = actualRamID;                    /* This foolishness handles ID=10 RAM disks. */
  468.         NoRamDisk();
  469.         ramID = oldRamID;
  470.         
  471.         if( itemHit == alreadyINew ) {
  472.             GetCtrlFile( &ctrlFileName );
  473.             heapSize = *(long *)*GetResource( 'RAMD', 256 );
  474.             dirSize  = *(long *)*GetResource( 'RAMD', 257 );
  475.             ramStart = (Ptr)GetZone() + heapSize;
  476.             
  477.             InitRamDisk( heapSize, ramStart, dirSize );
  478.             ReStartUs();                        /* Never returns. */
  479.         }
  480.     }
  481.     
  482.     ExitToShell();
  483. }
  484.  
  485. /* //  */
  486. /* Check the application parameters for a control file:  a text file with
  487. our creator or a name ending in ".ram" (capitalization unimportant).  If
  488. such a file is found, we will use it to set up the RAM disk.
  489.  
  490. Since the context of this run is the control file, the current volume is
  491. set to the control file's volume.  Open the control file's resource fork;
  492. if one is not present, create it.  If the file's creator is not us, set it
  493. to us.  If the RAMD resource is not present in the file, copy it to the
  494. file. Save the index of the file for deleting it from the appl parms list;
  495. the rest of them will be available to the application we will launch. */
  496.  
  497. typedef struct {
  498.     short        message;
  499.     short        count;
  500.     char        fList;                            /* an array of variable length structures */
  501. } ApplParms;
  502.  
  503. typedef struct {
  504.     short        vRefNum;
  505.     long        type;
  506.     short        filler;
  507.     char        fName[2];                        /* actually length of name, plus filler to even length */
  508. } FEntry;
  509.  
  510.  
  511. long            fEntryIndex;
  512. short            fEntryLength;
  513.  
  514.  
  515. GetCtrlFile( nameP )
  516. char            **nameP;
  517. {
  518.     ApplParms    *applParmP;
  519.     FEntry        *fEntry;
  520.     short        i, j, k;
  521.     ioParam        pb;
  522.     fileParam    fpb;
  523.     char        suffix[MAXLINE];
  524.     short        resRefNum;
  525.     Handle        ramH;
  526.     
  527.     
  528.     *nameP = NULL;                                /* assume no control file */
  529.     
  530.     if( AppParmHandle ) {
  531.         HLock( AppParmHandle );
  532.         applParmP = *(ApplParms **)AppParmHandle;
  533.         
  534.         for( fEntry = (FEntry *)&applParmP->fList, i = 1;
  535.             i <= applParmP->count;
  536.             fEntry = (FEntry *)( (char *)fEntry + ((sizeof(FEntry) + fEntry->fName[0]) & ~0x1) ), ++i )
  537.         {
  538.             if( fEntry->type == 'TEXT' ) {
  539.                 Clear( fpb );
  540.                 fpb.ioNamePtr = (StringPtr)fEntry->fName;
  541.                 fpb.ioVRefNum = fEntry->vRefNum;
  542.                 PBGetFInfo( &fpb, FALSE );
  543.                 
  544.                 /* find extension (.xxx) */
  545.                 for( j = fEntry->fName[0];  j && fEntry->fName[j] != '.';  --j )
  546.                     ;
  547.                 
  548.                 suffix[0] = fEntry->fName[0] - j + 1;
  549.                 BlockMove( &fEntry->fName[j], &suffix[1], suffix[0] );
  550.                 
  551.                 if(     fpb.ioFlFndrInfo.fdCreator == RamSignature
  552.                     ||  EqualString(suffix, "\p.ram", FALSE, TRUE) )
  553.                 {
  554.                     *nameP = NewPtr( fEntry->fName[0] + 1 );
  555.                     BlockMove( fEntry->fName, *nameP, fEntry->fName[0]+1 );
  556.                     break;
  557.                 }
  558.             }
  559.         }
  560.         
  561.         if( *nameP ) {                            /* have a control file */
  562.             fEntryIndex = (char *)fEntry - (char *)applParmP;
  563.             fEntryLength = (sizeof(FEntry) + fEntry->fName[0]) & ~0x1;
  564.             
  565.             Clear( pb );
  566.             pb.ioVRefNum = fEntry->vRefNum;
  567.             PBSetVol( &pb, FALSE );
  568.             
  569.             if( (resRefNum = OpenResFile(*nameP)) < 0 ) /* ensure a resource fork */
  570.                 CreateResFile( *nameP );
  571.             
  572.             ramH = GetResource( 'RAMD', 256 );    /* ensure a size resource */
  573.             if( HomeResFile(ramH) != resRefNum ) {
  574.                 if( !HandToHand(&ramH) ) {
  575.                     AddResource( ramH, 'RAMD', 256, "\p" );
  576.                     UpdateResFile( resRefNum );
  577.                 }
  578.             }
  579.             
  580.             ramH = GetResource( 'RAMD', 257 );    /* ensure a dir size resource */
  581.             if( HomeResFile(ramH) != resRefNum ) {
  582.                 if( !HandToHand(&ramH) ) {
  583.                     AddResource( ramH, 'RAMD', 257, "\p" );
  584.                     UpdateResFile( resRefNum );
  585.                 }
  586.             }
  587.             
  588.             if( fpb.ioFlFndrInfo.fdCreator != RamSignature ) {
  589.                 fpb.ioFlFndrInfo.fdCreator = RamSignature;
  590.                 PBSetFInfo( &fpb, FALSE );
  591.             }
  592.         }
  593.         
  594.         HUnlock( AppParmHandle );
  595.     }
  596. }
  597.  
  598. /* //  */
  599. /* Remove the control file from the appl parms -- remove it entirely, don't
  600. just zero its type -- and point all remaining files to the RAM disk, as we
  601. expect they were copied there and the volume they were on has just been
  602. ejected.  This is a separate routine from GetCtrlFile() because that is
  603. called once in each pass. */
  604.  
  605. ZapControlFile( ramDrvNum )
  606. short            ramDrvNum;
  607. {
  608.     ApplParms    *applParmP;
  609.     FEntry        *fEntry;
  610.     short        i;
  611.     
  612.     
  613.     if( AppParmHandle  &&  fEntryLength ) {        /* Remove command file. */
  614.         Munger( AppParmHandle,
  615.             fEntryIndex,
  616.             NULL,
  617.             fEntryLength,
  618.             "",
  619.             0 );
  620.         
  621.         --(*(ApplParms **)AppParmHandle)->count;
  622.     }
  623.     
  624.     
  625.     applParmP = *(ApplParms **)AppParmHandle;
  626.     
  627.     for( fEntry = (FEntry *)&applParmP->fList, i = 1; /* set volume on parm files */
  628.          i <= applParmP->count;
  629.          fEntry = (FEntry *)( (char *)fEntry + ((sizeof(FEntry) + fEntry->fName[0]) & ~0x1) ), ++i )
  630.     {
  631.         fEntry->vRefNum = ramDrvNum;            /* claim the file is on the RAM disk */
  632.     }
  633. }
  634.  
  635. /* //  */
  636. /* Reserve memory for the RAM disk.  The top of useable memory is available
  637. in BufPtr, which we save and then set lower to reserve memory.  BufPtr is
  638. observed by InitApplZone(). */
  639.  
  640. InitRamDisk( heapSize, ramStart, dirSize )        /* Called also by GetNewSize(). */
  641. long            heapSize;                        /* --> */
  642. Ptr                ramStart;                        /* --> */
  643. long            dirSize;                        /* --> */
  644. {
  645.     if( dirSize < 1  ||  dirSize > 10 )
  646.         dirSize = 1;
  647.     
  648.     applInfo.signature = RamSignature;
  649.     applInfo.oldBufPtr = ramInfo.oldBufPtr = BufPtr; /* The driver looks here. */
  650.     applInfo.initCmd   = 'BD';
  651.     applInfo.initVal   = dirSize;
  652.     
  653.     if( (applInfo.oldBufPtr - ramStart) < MinDisk ) {
  654.         if( ((applInfo.oldBufPtr - ramStart)  +  (heapSize - MinHeap)) < MinDisk ) {
  655.             Alert( (MemTop == ThinMemTop) ? (short)alrtThinNoRoom : alrtFatNoRoom, NULL );
  656.             ExitToShell();
  657.         }
  658.         else {                                    /* Can make it big enough to use. */
  659.             Alert( alrtSizeChange, NULL );
  660.             MakeCtlW( MinDisk );
  661.             GetNewSize();
  662.         }
  663.     }
  664.     
  665.     BufPtr = ramInfo.ramDisk = ramStart;        /* Reserves RAM disk memory. */
  666. }
  667.  
  668.  
  669. /* Create a RAM disk in the reserved memory. */
  670.  
  671. short    MakeRamDisk()
  672. {
  673.     ioParam        pb;
  674.     
  675.     
  676.     Clear( pb );
  677.     pb.ioNamePtr = (StringPtr)RamName;            /* The driver is in our file. */
  678.     pb.ioPermssn = 3;                            /* Read and Write. */
  679.  
  680.     if( PBOpen( &pb, FALSE ) ) {
  681.         error("\pcan't open RAM disk driver, ioResult=^2", (long)pb.ioResult);
  682.         ExitToShell();
  683.     }
  684.     
  685.     DetachResource( GetNamedResource('DRVR', pb.ioNamePtr) );    /* Keep in memory even after we quit. */ 
  686.     
  687.     
  688.     return( pb.ioRefNum );
  689. }
  690.  
  691. /* //  */
  692. /* Find an unused drive number.  Search the drive queue and find which
  693. drive numbers are already in use; then choose the smallest one beyond the
  694. Sony drives (>2).
  695.  
  696. The drive queue doesn't use a standard OS queue.  For some awful reason,
  697. a long word _before_ the link field contains flags, but the link still
  698. points to the next link field.  Sigh. */
  699.  
  700. /* Size must be a power of 2 */
  701. #define InUseSize 64
  702.  
  703. short    UnusedDrive()
  704. {
  705.     char        inUse[InUseSize];
  706.     short        i;
  707.     DrvQEl        *dqp;
  708.     
  709.     
  710.     /* Mark table entries for drive numbers in use. */
  711.     
  712.     aClear( inUse, InUseSize );
  713.     
  714.     for( dqp = (DrvQElPtr)DrvQHdr.qHead;  dqp;  dqp = (DrvQElPtr)dqp->qLink ) {
  715.         if( dqp->dQDrive > 0  &&  dqp->dQDrive < InUseSize )    /* array bounds check */
  716.             inUse[ dqp->dQDrive ] = TRUE;
  717.     }
  718.     
  719.     
  720.     /* Search table for an unused drive, not a Sony drive. */
  721.     
  722.     for( i = 3;  i < InUseSize;  ++i ) {
  723.         if( ! inUse[i] )
  724.             return( i );
  725.     }
  726.     
  727.     error("\pcan't find an unused drive number");
  728.     return( InUseSize );
  729. }
  730.  
  731. /* //  */
  732. /* Add a new drive and mount the RAM disk in it.  The drive is flagged as
  733. not write protected and not doing ejects.*/
  734.  
  735. ChgDrvQ( ramRefNum, ramDrvNum, size )
  736. short            ramRefNum;                        /* --> */
  737. short            ramDrvNum;                        /* --> */
  738. long            size;                            /* --> */
  739. {
  740.     DrvQElPtr    dqp;
  741.     ioParam        vpb;
  742.     long        *flagsPtr;
  743.     
  744.     
  745.     dqp = (DrvQElPtr)( NewPtrSysClr(sizeof(DrvQEl) + 4) + 4 );    /* DrvQEl with flags at front */
  746.     
  747.     AddDrive( ramRefNum, ramDrvNum, dqp );
  748.     flagsPtr = (long *)dqp - 1;
  749.     *flagsPtr = 0x00080000L;                    /* Not write protected, can't eject. */
  750.     dqp->dQDrvSize = size / 512;                /* fill in drive size for DI pkg */
  751.     
  752.     ramInfo.drvQEntry = (QElemPtr)dqp;
  753.     
  754.     Clear( vpb );
  755.     vpb.ioVRefNum = ramDrvNum;                    /* Drive to mount volume in. */
  756.     if( PBMountVol(&vpb) )
  757.         error("\pcan't mount the RAM disk, ioResult=^2", (long)vpb.ioResult);
  758. }
  759.  
  760.  
  761. /* This probably wouldn't be necessary if Apple documented the File
  762. Manager better.  If the boot disk is write-protected, the RAM disk is
  763. also!  It doesn't matter that the new drive says that it isn't protected.
  764. Here we clear that flag. */
  765.  
  766. FixVolInfo( ramDrvNum )
  767. short            ramDrvNum;                        /* --> */
  768. {
  769.     QElem        *vcbp;
  770.     
  771.     
  772.     vcbp = VCBQHdr.qHead;
  773.     
  774.     while( TRUE ) {
  775.         if( *(short *)&vcbp->qData[72-6] == ramDrvNum ) {    /* Is volume in our drive? */
  776.             *(short *)&vcbp->qData[18-6] &= ~0x0080;        /* un-write protect it */
  777.             break;
  778.         }
  779.         
  780.         if( ! (vcbp = vcbp->qLink) )
  781.             error("\pcan't find RAM disk to un-write protect it");
  782.     }
  783. }
  784.  
  785. /* //  */
  786. /* Launch the finder on the RAM disk.  The method was cribbed from Apple's
  787. (pre-HFS) Finder. */
  788.  
  789. LaunchRamDisk( ramDrvNum, exitAppl )
  790. short            ramDrvNum;                        /* --> */
  791. char            *exitAppl;                        /* --> */
  792. {
  793.     volumeParam    pb;
  794.     QElem        *vcbp;
  795.     
  796.     
  797.     Clear( pb );                                /* Flush the RAM disk. */
  798.     pb.ioVRefNum = ramDrvNum;
  799.     PBFlshVol( &pb, FALSE );
  800.     
  801.     pb.ioVRefNum = OurDriveNum();
  802.     if( pb.ioVRefNum == 1  ||  pb.ioVRefNum == 2 ) {    /* Mac SE/II:  may not refer to sony drives */
  803.         PBEject( &pb );                            /* Eject the disk.  We assume that this was the */
  804.         PBUnmountVol( &pb );                    /*    only mounted disk besides the RAM disk. */
  805.         /* System 4.2: disk won't unmount because our app is still open. */
  806.     }
  807.     
  808. /* //  */
  809.     /* Set the default volume to the RAM disk and launch _its_ Finder.  Key
  810.     parts of this code were cribbed from the Finder. */
  811.     
  812.     pb.ioVRefNum = ramDrvNum;
  813.     PBSetVol( &pb, FALSE );
  814.     
  815.     DetachResource( GetResource('CODE', 2) );    /* Us, so we don't go away when the */
  816.     CloseResFile( 0 );                            /*   old system file is closed. */
  817.     ResErrProc = 0;                                /* Finder magic. */
  818.     InitResources();                            /* new system file */
  819.     InitFonts();
  820.     BootDrive = ramDrvNum;                        /* Finder magic. */
  821.     PBSetVol( &pb, FALSE );                        /* Finder magic. */
  822.     
  823.     Launch( 0, exitAppl );
  824. }
  825.  
  826.  
  827. /* Start us over again.  This re-initializes the application heap, which is
  828. when BufPtr is observed so RAM disk memory is reserved. */
  829.  
  830. ReStartUs()
  831. {
  832.     Launch( 0, CurApName );                        /* We shall return. */
  833. }
  834.  
  835. /* //  */
  836. /* Remove any RAM disk.  Each of the actions below is (almost always) safe,
  837. even if it doesn't work in some circumstances.  If an error occurs, there
  838. isn't much to be done about it, so most are ignored.  We are paranoid about
  839. other disk drivers, etc. */
  840.  
  841. NoRamDisk()
  842. /* extern RamInfo ramInfo; */                    /* --> */
  843. {
  844.     register DrvQElPtr    dqp;
  845.     ioParam                pb;
  846.     register short        sigWord;
  847.     
  848.  
  849.     SetCursor( *GetCursor(watchCursor) );
  850.     
  851.     
  852.     if( BufPtr == ramInfo.ramDisk )
  853.         BufPtr = ramInfo.oldBufPtr;                /* Restore mem top so all memory is available. */
  854.     
  855.     
  856.     if( ramInfo.drvQEntry ) {
  857.         dqp = (DrvQElPtr)ramInfo.drvQEntry;
  858.     
  859.         /* Remove everything we can find. */
  860.         
  861.         Clear( pb );                            /* Get rid of the disk, */
  862.         pb.ioVRefNum = dqp->dQDrive;
  863.         if( PBUnmountVol(&pb) )
  864.             error( "\pNoRamDisk() can't unmount RAM disk, ioResult=^2", (long)pb.ioResult );
  865.         
  866.         Dequeue( dqp, &DrvQHdr );                /*   the drive, */
  867.         DisposPtr( (char *)dqp - 4 );
  868.         
  869.         pb.ioRefNum = ~ramID;                    /*   and the driver. */
  870.         PBClose( &pb, FALSE );
  871.     }
  872.     
  873.     
  874.     /* Tell the RAM disk driver (next time) that the disk is not set up. */
  875.     
  876.     sigWord = *(short *)&ramInfo.ramDisk[SigWord];
  877.     
  878.     if( ramInfo.ramDisk  &&  (sigWord == 0xd2d7  ||  sigWord == 0x4244) )
  879.         *(short *)&ramInfo.ramDisk[SigWord] = 0xFFFF;    /* Tells RAM disk driver. */
  880. }
  881.  
  882. /* //  */
  883. error( err, m1, m2, str )
  884. char            *err;
  885. long            m1, m2;                            /* message data that may have been sent */
  886. char            *str;
  887. {
  888.     char        s1[32], s2[32];
  889.     
  890.     
  891.     if( TraceTrap < ROMBase )
  892.         DebugStr( err );
  893.     
  894.     NumToString( m1, s1 );
  895.     NumToString( m2, s2 );
  896.     ParamText( err, str, s1, s2 );
  897.     
  898.     if( Alert(128, NULL) == 1 ) {
  899.         NoRamDisk();
  900.         ExitToShell();
  901.     }
  902. }
  903.  
  904. /* //  */
  905. /* Variant form of NewPtr. */
  906.  
  907. short    NewPtrSysClrCode[5] = { 0x202F, 0x0004,    /* move.l    4(sp),d0    */
  908.                                 0xA71E,            /* _NewPtr,SYS,CLR        */
  909.                                 0x2008,            /* move.l    a0,d0        */
  910.                                 0x4E75 };        /* rts                    */
  911.  
  912.  
  913. /* Clear a block of memory. */
  914.  
  915. aClear( p, len )
  916. register Ptr    p;
  917. register short    len;
  918. {
  919.     while( len-- )
  920.         *p++ = 0;
  921. }
  922.